/*
 * Date：10/23/18 10:15 PM
 * Author: guomw
 *
 */

package com.treasure.mall.biz.service.core.auth.impl;

import com.treasure.mall.biz.entity.auth.SystemManager;
import com.treasure.mall.biz.entity.auth.SystemMenu;
import com.treasure.mall.biz.entity.auth.SystemRole;
import com.treasure.mall.biz.repository.system.SystemManagerRepository;
import com.treasure.mall.biz.repository.system.SystemMenuRepository;
import com.treasure.mall.biz.repository.system.SystemRoleRepository;
import com.treasure.mall.biz.service.core.auth.SystemService;
import com.treasure.mall.zbq.common.base.TwoTuple;
import com.treasure.mall.zbq.common.constant.Constant;
import com.treasure.mall.zbq.common.ienum.RoleType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletRequest;
import java.text.MessageFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author guomw
 * @date 2018/9/17
 */
@Service
public class SystemServiceImpl implements SystemService {

    private static Log log = LogFactory.getLog(SystemServiceImpl.class);

    @Autowired
    private SystemMenuRepository systemMenuRepository;
    @Autowired
    private SystemRoleRepository systemRoleRepository;
    @Autowired
    private SystemManagerRepository systemManagerRepository;

    /**
     * 获取当前用户的菜单权限
     *
     * @param userId 用户ID
     * @return 菜单列表
     */
    @Override
    public List<SystemMenu> findByUserId(Integer userId) {
        SystemManager manager = systemManagerRepository.findById(userId).orElse(null);
        if (manager == null) {
            return null;
        }
        List<SystemMenu> menus = systemMenuRepository.findAll();
        if (menus != null && menus.size() > 0) {
            //排序
            menus.sort(Comparator.comparingInt(SystemMenu::getItemSort));
        }
        List<SystemMenu> userMenus;
        /**
         * 角色校验逻辑
         * 1、判断当前用户是否有角色
         * 2、判断用户角色是否为系统默认角色
         * 3、判断用户角色是否为用户创建
         */
        if (manager.getRole().getRoleType() == RoleType.Default.getCode()) {
            return menus;
        }
        //获取用户角色
        SystemRole role = manager.getRole();
        //如果角色没有启用，则返回空
        if (role == null || !role.isEnable()) {
            return null;
        }

        //获取当前用户可用菜单
        userMenus = menus.stream().filter(r -> {
                    if (r.isItemEnable()) {
                        return role.getAuthority().contains(MessageFormat.format("|{0}|", r.getItemCode()));
                    }
                    return false;
                }
        ).collect(Collectors.toList());
        //排序
        userMenus.sort(Comparator.comparingInt(SystemMenu::getItemSort));
        return userMenus;
    }

    /**
     * 更新菜单启用状态
     *
     * @param itemCode
     * @return
     */
    @Override
    public boolean updateEnableByItemCode(Integer itemCode) {
        SystemMenu menu = this.findByItemCode(itemCode);
        if (menu != null) {
            return systemMenuRepository.updateEnableByItemCode(menu.getItemCode(), !menu.isItemEnable()) > 0;
        }
        return false;
    }

    /**
     * 根据code，获取菜单信息
     *
     * @param itemCode 菜单code
     * @return 菜单实体
     */
    @Override
    public SystemMenu findByItemCode(Integer itemCode) {
        return systemMenuRepository.findById(itemCode).orElse(null);
    }


    /**
     * 保存菜单
     *
     * @param systemMenu 菜单实体信息
     * @return
     */
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public SystemMenu save(SystemMenu systemMenu) {
        systemMenuRepository.save(systemMenu);
        systemMenu = updateItemParentChildCount(systemMenu);
        return systemMenu;
    }

    /**
     * 删除菜单
     *
     * @return boolean
     * @Param [itemCode]
     * @Author guomw
     * @Date 2018/9/17 13:54
     **/
    @Transactional(rollbackFor = RuntimeException.class)
    @Override
    public boolean deleteByItemCode(Integer itemCode) {
        SystemMenu systemMenu = findByItemCode(itemCode);
        if (systemMenu != null) {
            if (systemMenu.getItemChildCount() == null || systemMenu.getItemChildCount() == 0) {
                systemMenuRepository.deleteById(itemCode);
                updateItemParentChildCount(systemMenu);
                return true;
            }
        }
        return false;
    }

    /**
     * 更新父级的子节点数
     *
     * @param systemMenu
     * @return
     */
    private SystemMenu updateItemParentChildCount(SystemMenu systemMenu) {
        Integer pid = systemMenu.getItemParentCode();
        if (pid > 0) {
            Specification<SystemMenu> specification = (root, criteriaQuery, criteriaBuilder) ->
                    criteriaBuilder.and(criteriaBuilder.equal(root.get("itemParentCode").as(Integer.class), pid));
            systemMenu = systemMenuRepository.findById(pid).orElse(null);
            systemMenu.setItemChildCount(systemMenuRepository.count(specification));
        }
        return systemMenu;
    }


    /**
     * 获取当前用户的角色
     * 如果当前登录的用户不是超级管理员，则获取该用户的角色数据
     *
     * @param userId 用户ID
     * @return
     * @author guomw
     * @date 2018/9/17 14:07
     **/
    @Override
    public List<SystemRole> findRoleByUserId(Integer userId) {
        SystemManager manager = systemManagerRepository.findById(userId).orElse(null);
        if (manager == null) {
            return null;
        }
        if (manager.getRole().getRoleType() == RoleType.Default.getCode()) {
            userId = -1;
        }
        Integer finalUserId = userId;
        return systemRoleRepository.findAll((root, query, builder) -> builder.and(builder.equal(root.get("userId").as(Integer.class), finalUserId)));
    }

    /**
     * 获取角色信息
     *
     * @param roleId 角色ID
     * @return
     * @author guomw
     * @date 2018/9/17 14:17
     **/
    @Override
    public SystemRole findRoleById(Integer roleId) {
        return systemRoleRepository.findById(roleId).orElse(null);
    }

    /**
     * 更新角色
     *
     * @param role 角色数据实体
     * @return
     * @author guomw
     * @date 2018/9/17 14:09
     **/
    @Override
    public SystemRole saveRole(SystemRole role) {
        //如果groupId 为空或0时，则需要判断当前用户身份
        if (role.getRoleId() == null || role.getRoleId() == 0) {
            if (role.getUserId() > 0) {
                SystemManager manager = systemManagerRepository.findById(role.getUserId()).orElse(null);
                if (manager == null) {
                    return null;
                }
                if (manager.getRole().getRoleType() == RoleType.Default.getCode()) {
                    role.setUserId(-1);
                }
            }
        }
        return systemRoleRepository.save(role);
    }

    /**
     * 删除角色
     *
     * @param roleId 角色ID
     * @param userId 用户ID
     * @return
     * @author guomw
     * @date 2018/9/17 14:25
     **/
    @Override
    public boolean deleteRoleById(Integer roleId, Integer userId) {
        SystemManager manager = systemManagerRepository.findById(userId).orElse(null);
        if (manager == null) {
            return false;
        }
        if (manager.getRole().getRoleType() == RoleType.Default.getCode()) {
            systemRoleRepository.deleteById(roleId);
            return true;
        }
        //如果不是管理员身份，则需判断当前删除节点是否属于用户
        Specification<SystemRole> specification = (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(builder.equal(root.get("roleId").as(Integer.class), roleId));
            predicates.add(builder.equal(root.get("userId").as(Integer.class), userId));
            return builder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        SystemRole role = systemRoleRepository.findOne(specification).orElse(null);
        if (role != null) {
            systemRoleRepository.deleteById(roleId);
            return true;
        }
        return false;
    }

    /**
     * 更新角色启用状态
     *
     * @param roleId
     * @return
     */
    @Override
    public boolean updateEnableByRoleId(Integer roleId) {
        SystemRole role = this.findRoleById(roleId);
        if (role != null) {
            return systemRoleRepository.updateEnableById(role.getRoleId(), !role.isEnable()) > 0;
        }
        return false;
    }

    /**
     * 保存管理员信息
     *
     * @param manager
     * @return
     */
    @Override
    public SystemManager saveManager(SystemManager manager) {
        return systemManagerRepository.save(manager);
    }

    /**
     * 获取管理员信息
     *
     * @param userId
     * @return
     */
    @Override
    public List<SystemManager> findByParentUserId(Integer userId) {

        return systemManagerRepository.findAll((root, query, builder) -> builder.and(builder.equal(root.get("parentUserId").as(Integer.class), userId)));
    }

    /***
     * 启用或禁用账户状态
     * @param UserId
     * @return
     */
    @Override
    public boolean updateManagerEnableById(Integer UserId) {
        SystemManager manager = this.findManagerById(UserId);
        if (manager != null) {
            return systemManagerRepository.updateEnableById(manager.getUserId(), !manager.isEnable()) > 0;
        }
        return false;
    }

    /**
     * 查看管理员信息
     *
     * @param userId
     * @return
     */
    @Override
    public SystemManager findManagerById(Integer userId) {
        return systemManagerRepository.findById(userId).orElse(null);
    }

    @Override
    public SystemManager findManagerByLoginName(String loginName) {
        return systemManagerRepository.findOne((root, query, builder) -> builder.and(builder.equal(root.get("loginName").as(String.class), loginName))).orElse(null);
    }

    @Override
    public Integer getCurrentRootId(HttpServletRequest request) {
        Integer result = null;
        if (request == null) {
            return result;
        } else {
            SecurityContext ctx = (SecurityContext) request.getSession().getAttribute(Constant.SPRING_SECURITY_CONTEXT);
            if (ctx != null && ctx.getAuthentication() != null && ctx.getAuthentication().getPrincipal() instanceof UserDetails) {
                SystemManager manager = (SystemManager) ctx.getAuthentication().getPrincipal();
                Integer savedCustomerId = manager.getUserId();
                if (savedCustomerId != null) {
                    result = savedCustomerId;
                }
            }
            return result;
        }
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return findManagerByLoginName(username);
    }


    @Override
    public void modifyManagerPassword(Integer userId, String password) {
        systemManagerRepository.modifyPassword(userId, password);
    }

    @Override
    public boolean checkFunction(SystemManager manager, String path) {
        SystemRole role = manager.getRole();
        if (role.getRoleType() == -1) {
            return true;
        }
        SystemMenu menu = systemMenuRepository.findByItemPath(path);
        if (menu == null) {
            return true;
        }
        if (!StringUtils.isEmpty(role.getAuthority())) {
            return role.getAuthority().contains("|" + menu.getItemCode() + "|");
        }
        return false;
    }
}
